using CfgTable;
using IQIGame.Onigao.Framework;
using IQIGame.Onigao.Game;
using IQIGame.Onigao.GamePlay;
using NetProtocol.POD;
using System.Collections.Generic;

namespace IQIGame.Onigao.Logic
{
    /// <summary>
    /// 关卡buff管理器
    /// </summary>
    public class LevelBuffManager
    {
        private BaseLevelFunctionHost _host;
        private BetterLinkedList<LevelNormalBuff> _sortedBuffList = new BetterLinkedList<LevelNormalBuff>();
        private Dictionary<int, LevelNormalBuff> _buffMap = new Dictionary<int, LevelNormalBuff>();

        public LevelBuffManager(BaseLevelFunctionHost host)
        {
            _host = host;
        }

        public void InitBuffs(IReadOnlyList<LevelBuffPOD> buffPODs)
        {
            if (_sortedBuffList.Count != 0 || _buffMap.Count != 0)
            {
                LogicLog.LogError("初始化失败，已经有buff存在");
                return;
            }
            for (int i = 0; i < buffPODs.Count; i++)
            {
                LevelBuffPOD pod = buffPODs[i];
                LevelNormalBuff buff = ClassPool.Get<LevelNormalBuff>();
                CfgLevelBuff cfgLevelBuff = TableCenter.levelBuff.Get(pod.cid);
                buff.Init(_host, cfgLevelBuff);
                buff.SetData(pod.stack, pod.leftSec);
                _sortedBuffList.AddLast(buff);
                _buffMap.Add(buff.cfg.Id, buff);
            }
        }

        /// <summary>
        /// 添加buff
        /// </summary>
        /// <param name="buffCid"></param>
        /// <param name="changedBuff">添加完成后发生改变的buff，如果添加成功该值为已添加的buff，失败如果有值则为堆叠层数+1的buff，以上都不满足为null</param>
        /// <param name="removeBuffCid">添加过程中因为被新buff覆盖而移除的buff，如果没有则为0</param>
        /// <returns>是否成功添加buff（只有buff列表+1才算）</returns>
        public bool AddBuff(int buffCid, out LevelNormalBuff changedBuff, out int removeBuffCid)
        {
            changedBuff = null;
            removeBuffCid = 0;
            if (_buffMap.TryGetValue(buffCid, out LevelNormalBuff buff)) //处理叠加
            {
                if (buff.AddStack(1, false))
                {
                    changedBuff = buff;
                    return false;
                }
                return false;
            }
            //处理添加，需要按照触发优先级排序，还需要考虑覆盖的情况
            CfgLevelBuff cfgNewBuff = TableCenter.levelBuff.Get(buffCid);
            bool addSuccess = _sortedBuffList.Count == 0;
            //将要插入到它前面的节点
            BetterLinkedListNode<LevelNormalBuff> toInsertBeforeNode = null;
            //被覆盖的buff的节点（将要被移除的节点）
            BetterLinkedListNode<LevelNormalBuff> beCoveredNode = null;
            for (BetterLinkedListNode<LevelNormalBuff> node = _sortedBuffList.FirstNode; node != null; node = node.next)
            {
                LevelNormalBuff nodeValueBuff = node.value;
                //决定插入位置
                if (toInsertBeforeNode == null && cfgNewBuff.TriggerPriority < nodeValueBuff.cfg.TriggerPriority)
                {
                    toInsertBeforeNode = node;
                    addSuccess = true;
                }
                //判断覆盖优先级，决定能不能添加，如果能，则要删除之前同类型的buff
                if (cfgNewBuff.CoverType != 0 && nodeValueBuff.cfg.CoverType == cfgNewBuff.CoverType)
                {
                    if (cfgNewBuff.CoverPriority <= nodeValueBuff.cfg.CoverPriority) //覆盖原buff
                    {
                        beCoveredNode = node;
                    }
                    else //添加失败
                    {
                        addSuccess = false; //唯一集合不为空且toInsertBeforeNode == null的情况
                        break;
                    }
                }
                //如果找到了插入位置并且无需覆盖或找到了覆盖的buff，则跳出循环
                if (toInsertBeforeNode != null && (cfgNewBuff.CoverType == 0 || beCoveredNode != null))
                {
                    break;
                }
                //如果遍历到最后一个buff，既没有添加失败，也没有找到插入位置，则插入到最后
                if (node.next == null && toInsertBeforeNode == null)
                {
                    addSuccess = true;
                }
            }
            //处理覆盖时的移除
            if (beCoveredNode != null)
            {
                LevelNormalBuff oldBuff = beCoveredNode.value;
                removeBuffCid = oldBuff.cfg.Id;
                _sortedBuffList.RemoveNode(beCoveredNode);
                _buffMap.Remove(removeBuffCid);
                ClassPool.Put(oldBuff);
            }
            //添加buff
            if (addSuccess)
            {
                buff = ClassPool.Get<LevelNormalBuff>();
                buff.Init(_host, cfgNewBuff);
                _buffMap.Add(buff.cfg.Id, buff);
                if (_sortedBuffList.Count == 0)
                {
                    _sortedBuffList.AddFirst(buff);
                }
                else if (toInsertBeforeNode != null)
                {
                    _sortedBuffList.AddBefore(toInsertBeforeNode, buff);
                }
                else
                {
                    _sortedBuffList.AddLast(buff);
                }
                buff.OnAdd();
                changedBuff = buff;
                return true;
            }

            return false;
        }

        /// <summary>
        /// buff时间到会后移除buff的方法
        /// </summary>
        /// <param name="node"></param>
        private void RemoveBuffByLinkedNode(BetterLinkedListNode<LevelNormalBuff> node)
        {
            LevelNormalBuff buff = node.value;
            int buffCid = buff.cid;
            buff.OnRemove();
            _buffMap.Remove(buff.cfg.Id);
            _sortedBuffList.RemoveNode(node);
            ClassPool.Put(buff);

            LevelBuffChangeParam param = new LevelBuffChangeParam(GetHostType(), _host,
                                        LevelBuffOperationType.Remove,
                                        null, buffCid);
            List<LevelBuffChangeParam> changes = ListPool<LevelBuffChangeParam>.Get();
            changes.Add(param);
            _host.region.NotifyBuffChange(changes);
            ListPool<LevelBuffChangeParam>.Put(changes);
        }

        private LevelBuffHostType GetHostType()
        {
            if (_host is LevelPlayer)
            {
                return LevelBuffHostType.Player;
            }
            else if (_host is LevelEntity)
            {
                return LevelBuffHostType.Entity;
            }
            else if (_host is LevelHeroEntity)
            {
                return LevelBuffHostType.SingleHero;
            }
            return LevelBuffHostType.None;
        }

        public bool RemoveBuff(int cid)
        {
            if (_buffMap.TryGetValue(cid, out var buff))
            {
                buff.isExpired = true;
                return true;
            }
            return false;
        }

        public void RemoveAll()
        {
            for (var node = _sortedBuffList.FirstNode; node != null; node = node.next)
            {
                LevelNormalBuff buff = node.value;
                buff.OnRemove();
                _buffMap.Remove(buff.cfg.Id);
                ClassPool.Put(buff);
            }
            _sortedBuffList.Clear();
        }

        public bool AddBuffStack(int cid, int addValue, out LevelNormalBuff changeSuccessBuff)
        {
            changeSuccessBuff = null;
            if (_buffMap.TryGetValue(cid, out var buff))
            {
                if (buff.AddStack(addValue, true))
                {
                    changeSuccessBuff = buff;
                    return true;
                }
            }
            return false;
        }

        public bool ContainsBuff(int buffCid)
        {
            return _buffMap.ContainsKey(buffCid);
        }

        public void LogicOnUpdate()
        {
            for (var node = _sortedBuffList.FirstNode; node != null;)
            {
                LevelNormalBuff buff = node.value;
                buff.LogicOnUpdate();
                var mayRemoveNode = node;
                node = node.next; //required
                if (buff.isExpired)
                {
                    RemoveBuffByLinkedNode(mayRemoveNode);
                }
            }
        }

        public bool TryTriggerService(ServiceTriggerType triggerType)
        {
            bool hasSuccess = false;
            for (var node = _sortedBuffList.FirstNode; node != null; node = node.next)
            {
                LevelNormalBuff buff = node.value;
                if (!buff.isExpired && buff.TryTriggerService(triggerType))
                {
                    hasSuccess = true;
                }
            }
            return hasSuccess;
        }

        public List<LevelBuffPOD> GenerateBuffPODs()
        {
            if (_sortedBuffList.Count > 0)
            {
                List<LevelBuffPOD> list = new List<LevelBuffPOD>();
                for (var node = _sortedBuffList.FirstNode; node != null; node = node.next)
                {
                    LevelNormalBuff buff = node.value;
                    if (!buff.isExpired && (buff.leftFrame == -1 || buff.leftFrame > 0))
                    {
                        list.Add(buff.GeneratePOD() as LevelBuffPOD);
                    }
                }
                return list.Count > 0 ? list : null;
            }
            return null;
        }

        public float CalcSpeedRatio()
        {
            float ratio = 1;
            for (var node = _sortedBuffList.FirstNode; node != null; node = node.next)
            {
                LevelNormalBuff buff = node.value;
                if (!buff.isExpired)
                {
                    ratio *= buff.speedRatio;
                }
            }
            return ratio;
        }

        public void Clear()
        {
            for (var node = _sortedBuffList.FirstNode; node != null; node = node.next)
            {
                ClassPool.Put(node.value);
            }
            _buffMap.Clear();
            _sortedBuffList.Clear();
        }

        public void Dispose()
        {
            Clear();
        }
    }
}
